package adminservice

import (
	"errors"
	"fmt"
	"go-middle/app/common/model/menu"
	"go-middle/app/common/model/role_has_menu"
	"go-middle/library/response"

	"github.com/gogf/gf/database/gdb"
	"github.com/gogf/gf/frame/g"
	"github.com/gogf/gf/os/gtime"
	"github.com/gogf/gf/text/gstr"
)

//SystemInit 初始化结构体
type SystemInit struct {
	HomeInfo struct {
		Title string `json:"title"` //标题
		Href  string `json:"href"`  //标题跳转
	} `json:"homeInfo"`
	LogoInfo struct {
		Title string `json:"title"` //logo 标题
		Image string `json:"image"` //logo 图片
	} `json:"logoInfo"`
	MenuInfo []*menu.TreeListMenu `json:"menuInfo"` //菜单列表
}

//GetSystemInit 获取初始化数据
func GetSystemInit(uid int64, roles string) SystemInit {
	var systemInit SystemInit

	// 首页
	systemInit.HomeInfo.Title = "首页"
	systemInit.HomeInfo.Href = "/admin/system/home"

	// logo
	systemInit.LogoInfo.Title = "GO-MIDDLE"
	systemInit.LogoInfo.Image = "static/admin/images/logo.png"

	// 菜单
	systemInit.MenuInfo = GetMenuTree(uid, roles)

	return systemInit
}

//递归获取子菜单
func buildMenuChild(pid int, menuList []*menu.Entity) (out []*menu.TreeListMenu) {
	treeList := make([]*menu.TreeListMenu, 0)
	for _, v := range menuList {
		if pid == v.Pid {
			node := &menu.TreeListMenu{
				Entity: *v,
				Child:  nil,
			}
			child := buildMenuChild(v.Id, menuList)
			if child != nil {
				node.Child = child
			}
			treeList = append(treeList, node)
		}
	}
	return treeList
}

//递归获取子菜单
func buildMenuChildren(pid int, menuList []*menu.Entity, checked map[int]int) (out []*menu.TreeListPermission) {
	treeList := make([]*menu.TreeListPermission, 0)
	for _, v := range menuList {
		if pid == v.Pid {
			node := &menu.TreeListPermission{
				Entity:   *v,
				Checked:  false,
				Spread:   true,
				Disabled: true,
				Child:    nil,
			}
			if _, ok := checked[v.Id]; ok {
				node.Checked = true
				node.Disabled = false
			}
			child := buildMenuChildren(v.Id, menuList, checked)
			if child != nil {
				node.Child = child
			}
			treeList = append(treeList, node)
		}
	}
	return treeList
}

//CheckPermission 判断是否有权限
func CheckPermission(roles, route, method string) bool {
	cnt, _ := role_has_menu.Model.
		Where("role_id in (?)", gstr.Explode(",", roles)).
		As("a").
		InnerJoin(menu.Table+" b", "a.menu_id=b.id").
		Where("href = ? and method = ?", route, method).
		Where("delete_time=0 and status=1").
		Count()
	if cnt > 0 {
		return true
	}
	return false
}

//GetMenuTree 获取菜单列表
func GetMenuTree(uid int64, roles string) []*menu.TreeListMenu {
	m := menu.Model.Where("delete_time=0 and status=1 and is_menu=0")
	if uid != 1 {
		role, _ := role_has_menu.Model.
			Where("role_id in (?)", gstr.Explode(",", roles)).
			Array("menu_id")
		m = m.Where("id in (?)", role)
	}
	data, _ := m.Order("sort").FindAll()
	return buildMenuChild(0, data)
}

//GetPermissionTree 获取权限列表 tree
func GetPermissionTree(roleID int) []*menu.TreeListPermission {
	all, _ := menu.Model.Where("delete_time=0 and status=1").FindAll()
	checked, _ := role_has_menu.Model.Where("role_id=?", roleID).Array("menu_id")
	mp := make(map[int]int)
	for _, v := range checked {
		mp[v.Int()] = 1
	}
	return buildMenuChildren(0, all, mp)
}

//GetPermission 获取权限列表
func GetPermission() (count int, menuList []*menu.Entity) {
	m := menu.Model.Where("delete_time=0").Order("sort")
	count, _ = m.Count()
	_ = m.Structs(&menuList)
	return
}

//GetPermissionTreeSelect 获取权限列表 无限极分类
func GetPermissionTreeSelect() (tree []Tree) {
	m, _ := menu.Model.Where("delete_time=0 and status=1").FindAll()
	return createTree(m, 0, 0, "|— ")
}

//Tree 选择框树结构
type Tree struct {
	ID       int    `json:"value"`
	Pid      int    `json:"-"`
	Level    int    `json:"-"`
	LeftHTML string `json:"-"`
	Title    string `json:"label"`
}

func createTree(menuList []*menu.Entity, pid, level int, LeftHTML string) []Tree {
	var tmp []Tree
	for _, v := range menuList {
		if v.Pid == pid {
			lh := gstr.Repeat(LeftHTML, level)
			node := Tree{
				ID:       v.Id,
				Pid:      v.Pid,
				Level:    level + 1,
				LeftHTML: lh,
				Title:    lh + v.Title,
			}
			tmp = append(tmp, node)
			tmp2 := createTree(menuList, v.Id, level+1, LeftHTML)
			tmp = append(tmp, tmp2...)
		}
	}
	return tmp
}

//GetAdminRouteMap 获取admin模块需要鉴权的所有路由,用于前端编辑菜单选择
func GetAdminRouteMap() []response.LabelValue {
	list := g.Server().GetRouterArray()
	var m []response.LabelValue
	for _, v := range list {
		ck1 := gstr.Contains(v.Middleware, "middleware.CheckLoginAdminWeb")
		ck2 := gstr.Contains(v.Middleware, "middleware.CheckLoginAdminApi")
		if !ck1 && !ck2 {
			continue
		}
		str := EncodeAdminRoute(v.Method, v.Route)
		m = append(m, response.LabelValue{
			Label: str,
			Value: str,
		})
	}
	return m
}

//EncodeAdminRoute 组装前端显示路由
func EncodeAdminRoute(method, href string) string {
	return fmt.Sprintf("[%s]%s", method, href)
}

//解析前端显示路由
func decodeAdminRoute(route string) (method, href string) {
	if route != "" {
		tmp := gstr.Explode("]", route)
		href = tmp[1]
		method = tmp[0][1:]
	}
	return
}

//GetMenuByID 获取菜单信息
func GetMenuByID(id int64) *menu.Entity {
	data, _ := menu.Model.FindOne("id=?", id)
	return data
}

//SaveMenu 保存菜单信息
func SaveMenu(info interface{}) error {
	add, ok1 := (info).(menu.ReqAdd)
	edit, ok2 := (info).(menu.ReqEdit)
	if !ok1 && !ok2 {
		return errors.New("参数类型错误")
	}
	if ok2 {
		mode, _ := menu.FindOne("id=?", edit.Id)
		method, href := decodeAdminRoute(edit.Route)
		//编辑
		mode.Pid = edit.Pid
		mode.Title = edit.Title
		mode.Icon = edit.Icon
		mode.Href = href
		mode.Method = method
		mode.Sort = edit.Sort
		mode.Target = edit.Target
		mode.IsMenu = edit.IsMenu
		mode.Status = edit.Status
		mode.Remark = edit.Remark
		mode.UpdateTime = gtime.Now().Unix()
		_, err := mode.Update()
		if err != nil {
			return err
		}
	} else {
		var mode menu.Entity
		method, href := decodeAdminRoute(add.Route)
		//新增
		mode.Pid = add.Pid
		mode.Title = add.Title
		mode.Icon = add.Icon
		mode.Href = href
		mode.Method = method
		mode.Sort = add.Sort
		mode.Target = add.Target
		mode.IsMenu = add.IsMenu
		mode.Status = add.Status
		mode.Remark = add.Remark
		mode.CreateTime = gtime.Now().Unix()
		mode.UpdateTime = gtime.Now().Unix()
		_, err := mode.Insert()
		if err != nil {
			return err
		}
	}
	return nil
}

//DelMenu 删除菜单
func DelMenu(id int64) error {
	_, err := menu.Model.Where("id=?", id).Data(gdb.Map{
		"delete_time": gtime.Now().Unix(),
	}).Update()
	return err
}
